﻿#include "../ctlFont.h"
#include "../x/textpack.h"
#include "../ctlHelp.h"

namespace swui
{
	void* ctlFont::getNativeHandle()
	{
		return reinterpret_cast<void*>(_fontInstance);
	}
	unsigned ctlFont::getMaxCharWidth()
	{
		TEXTMETRICW met;
		GetTextMetricsW(_testDC.hdc, &met);
		return met.tmMaxCharWidth;
	}
	unsigned ctlFont::getAveCharWidth()
	{
		TEXTMETRICW met;
		GetTextMetricsW(_testDC.hdc, &met);
		return met.tmAveCharWidth;
	}
	int ctlFont::getTextExtentPoint(std::wstring::const_pointer text, 
			unsigned textLength, unsigned width, ctlPoint* pt)
	{
		int result;
		SIZE sz;
		GetTextExtentExPointW(_testDC.hdc, text, textLength, width, &result, 0, &sz);
		if(pt) *pt = ctlPoint(sz.cx, sz.cy);
		return result;
	}
	std::vector<int> ctlFont::getTextExtentDistance(std::wstring::const_pointer text, 
			unsigned textLength, unsigned width, ctlPoint* pt)
	{
		if(textLength == 0)
			return std::vector<int>();
		int result;
		SIZE sz;
		std::vector<int> dresult;
		if(width != 0xffffffff)
		{
			GetTextExtentExPointW(_testDC.hdc, text, textLength, width, &result, 0, &sz);
			std::vector<int> dis(result);
			GetTextExtentExPointW(_testDC.hdc, text, textLength, width, &result, &dis[0], &sz);
			if(pt) *pt = ctlPoint(sz.cx, sz.cy);
			dresult = std::move(dis);
		} else {
			std::vector<int> dis(textLength);
			GetTextExtentExPointW(_testDC.hdc, text, textLength, width, NULL, &dis[0], &sz);
			if(pt) *pt = ctlPoint(sz.cx, sz.cy);
			dresult = std::move(dis);
		}
		int pre = 0;
		for(int& elem : dresult)
		{
			int temp = elem;
			elem -= pre;
			pre = temp;
		}
		return std::move(dresult);
	}
	std::shared_ptr<ctlFont> ctlFont::clone()
	{
		return createFont(getFontSize(), getFontStyle(), 
			getFontWeight(), _fontData.lfFaceName);
	}
	unsigned ctlFont::getFontHeight()
	{
		TEXTMETRICW met;
		GetTextMetricsW(_testDC.hdc, &met);
		return met.tmHeight;
	}
	ctlFont::~ctlFont()
	{
		if(_fontInstance)
			DeleteObject(_fontInstance);
	}
	ctlFont::ctlFont(unsigned fontSize, fontStyle style, 
		fontWeight weight, const ctlText& fontName) : _testDC(1, 1)
	{
		memset(&_fontData, 0, sizeof(_fontData));
		setFontSize(fontSize);
		setFontStyle(style);
		setFontWeight(weight);
		setFontFamily(fontName);
		_fontInstance = 0;
	}
	bool ctlFont::setFontFamily(const ctlText& fontName)
	{
		if(fontName.length() >= LF_FACESIZE)
			return false;
		_ctlInterior::textpack pack;
		pack.set(fontName);
		pack.get(_fontData.lfFaceName, LF_FACESIZE);
		return true;
	}
	void ctlFont::setFontStyle(ctlFont::fontStyle type)
	{
		_fontData.lfItalic = (unsigned)type & (unsigned)fontStyle::italic ? TRUE : FALSE;
		_fontData.lfUnderline = (unsigned)type & (unsigned)fontStyle::underline ? TRUE : FALSE;
		_fontData.lfStrikeOut = (unsigned)type & (unsigned)fontStyle::strikeout ? TRUE : FALSE;
	}
	void ctlFont::setFontWeight(ctlFont::fontWeight type)
	{
		_fontData.lfWeight = (unsigned)type;
	}
	void ctlFont::setFontSize(unsigned fontSize)
	{
		_exactHeight = fontSize;
	}
	unsigned ctlFont::getWideFontFamily(std::wstring::pointer outData, unsigned len)
	{
		if(outData == 0) return 0;
		unsigned pos;
		for(pos = 0; pos < LF_FACESIZE && pos < len &&
					_fontData.lfFaceName[pos]; ++pos)
			outData[pos] = _fontData.lfFaceName[pos];
		return pos;
	}
	unsigned ctlFont::getFontFamily(char* outData, unsigned len)
	{
		_ctlInterior::textpack pack;
		pack.set(_fontData.lfFaceName);
		return pack.get(outData, len);
	}
	ctlFont::fontStyle ctlFont::getFontStyle()
	{
		fontStyle value = fontStyle::none;
		if(_fontData.lfItalic) value = fontStyle((unsigned)value | (unsigned)fontStyle::italic);
		if(_fontData.lfUnderline) value = fontStyle((unsigned)value | (unsigned)fontStyle::underline);
		if(_fontData.lfStrikeOut) value = fontStyle((unsigned)value | (unsigned)fontStyle::strikeout);
		return value;
	}
	ctlFont::fontWeight ctlFont::getFontWeight()
	{
		return (fontWeight)_fontData.lfWeight;
	}
	unsigned ctlFont::getFontSize()
	{
		return _exactHeight;
	}
	void ctlFont::flush()
	{
		if(_fontInstance)
			DeleteObject(_fontInstance);
		_fontData.lfHeight = -MulDiv(_exactHeight, GetDeviceCaps(_testDC.hdc, LOGPIXELSY), 72);
		_fontInstance = CreateFontIndirectW(&_fontData);
		SelectObject(_testDC.hdc, _fontInstance);
	}
	template<typename T1, typename T2, typename T3>
	ctlPoint ctlFont::__getTextSize(T1 drawtext, T2 calclen, T3 text, int len, bool calcItalic)
	{
		if(text == nullptr || *text == 0)
			return ctlPoint(0, 0);
		RECT rc = {0};
		drawtext(_testDC.hdc, text, len, &rc, DT_CALCRECT | DT_NOPREFIX);
		if(calcItalic && enumTypeAnd(getFontStyle(), fontStyle::italic) != fontStyle::none)
		{
			RECT rc2 = {0};
			int llen = len == -1 ? calclen(text) : len;
			drawtext(_testDC.hdc, text + llen - 1,
				-1, &rc2, DT_CALCRECT | DT_NOPREFIX);
			rc.right += rc2.right >> 1;
		}
		return ctlPoint(rc.right, rc.bottom);
	}
	ctlPoint ctlFont::getTextSize(const char* text, int len, bool calcItalic)
	{
		return __getTextSize(DrawTextA, strlen, text, len, calcItalic);
	}
	ctlPoint ctlFont::getTextSize(std::wstring::const_pointer text, int len, bool calcItalic)
	{
		return __getTextSize(DrawTextW, wcslen, text, len, calcItalic);
	}
}